/*
 * WaveConvert
 * Copyright (c) 2011 Shun Moriya <shun@mnu.sakura.ne.jp>
 *
 * The MIT License
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "WaveConvert.h"
#include <string.h>

WaveConvert::WaveConvert(void)
{
}

WaveConvert::~WaveConvert(void)
{
}

WaveConvert::Status WaveConvert::convert(FILE* out, FILE* in)
{
	AudioDataHeader audioDataHeader;

	memset(&audioDataHeader, 0, sizeof(audioDataHeader));

	if(memcmp(get_bytes(in, 4), "RIFF", 4) != 0)
		return NOT_RIFF_FORMAT;

	unsigned long riffSize = get_ulong(in);

	if(memcmp(get_bytes(in, 8), "WAVEfmt ", 8) != 0)
		return NOT_WAVE_FOMRAT;

	unsigned long waveSize = get_ulong(in);

	unsigned short dataType = get_ushort(in);
	if(dataType != 1)
		return NOT_PCM_FORMAT;

	unsigned short channels = get_ushort(in);			// 1 = mono, 2 = stereo
	unsigned long samplingRate = get_ulong(in);			// Sampling rate = %luHz
	unsigned long bytesPerSecond = get_ulong(in);		// Bytes / second
	unsigned short bytesPerChannels = get_ushort(in);	// Bytes x channels
	unsigned short bitsPerSample = get_ushort(in);		// Bits / sample
	if(0 < waveSize - 16)
	{
		if(fseek(in, waveSize - 16, SEEK_CUR) != 0)
			return FILE_SEEK_ERROR;
	}

	void* data = NULL;
	unsigned int dataSize = 0;

	{
		unsigned char s[5];
		while(fread(s, 4, 1, in) == 1)
		{
			unsigned long chunkSize = get_ulong(in);

			if(memcmp(s, "data", 4) == 0)
			{
				if(data != NULL)
				{
					free(data);
					return NOT_ENOUGH_MEMORY;
				}

				data = malloc(chunkSize);
				if(data == NULL)
				{
					free(data);
					return NOT_ENOUGH_MEMORY;
				}
				dataSize = chunkSize;
				if(fread(data, 1, dataSize, in) != dataSize)
				{
					free(data);
					return FILE_READ_ERROR;
				}
			}
			else
			{
				if(fseek(in, chunkSize, SEEK_CUR) != 0)
				{
					free(data);
					return FILE_SEEK_ERROR;
				}
			}
		}
	}

	audioDataHeader.bitsPerSample = static_cast<unsigned char>(bitsPerSample);
	audioDataHeader.numberChannel = static_cast<unsigned char>(channels);
	audioDataHeader.samplingRate = static_cast<unsigned int>(samplingRate);
	audioDataHeader.size = dataSize;
	audioDataHeader.loop = 0;

	if(fwrite(&audioDataHeader, sizeof(audioDataHeader), 1, out) != 1)
	{
		return FILE_WRITE_ERROR;
	}

	if(fwrite(data, dataSize, 1, out) != 1)
	{
		return FILE_WRITE_ERROR;
	}

	free(data);

	return SUCCESS;
}
